home *** CD-ROM | disk | FTP | other *** search
/ Die Speccy' 97 / Die Speccy' 97.iso / amiga_system / the_aminet / dev / lang / python020.lha / python / lib / formatter.py < prev    next >
Text File  |  1995-10-22  |  7KB  |  301 lines

  1. import regex
  2. import regsub
  3. import string
  4. import sys
  5.  
  6.  
  7. AS_IS = None
  8.  
  9. whitespace = '[' + string.whitespace + ']+'
  10.  
  11.  
  12. class NullFormatter:
  13.  
  14.     def __init__(self): pass
  15.     def end_paragraph(self, blankline): pass
  16.     def add_line_break(self): pass
  17.     def add_hor_rule(self): pass
  18.     def add_label_data(self, format, counter): pass
  19.     def add_flowing_data(self, data): pass
  20.     def add_literal_data(self, data): pass
  21.     def flush_softspace(self): pass
  22.     def push_font(self, x): pass
  23.     def pop_font(self): pass
  24.     def push_margin(self, margin): pass
  25.     def pop_margin(self): pass
  26.     def set_spacing(self, spacing): pass
  27.     def push_style(self, style): pass
  28.     def pop_style(self): pass
  29.  
  30.  
  31. class AbstractFormatter:
  32.  
  33.     def __init__(self, writer):
  34.     self.writer = writer        # Output device
  35.     self.font_stack = []        # Font state
  36.     self.margin_stack = []        # Margin state
  37.     self.spacing = None        # Vertical spacing state
  38.     self.style_stack = []        # Other state, e.g. color
  39.     self.nospace = 1        # Should leading space be suppressed
  40.     self.softspace = 0        # Should a space be inserted
  41.  
  42.     def end_paragraph(self, blankline):
  43.     if not self.nospace:
  44.         self.writer.send_paragraph(blankline)
  45.     self.nospace = 1
  46.     self.softspace = 0
  47.  
  48.     def add_line_break(self):
  49.     self.writer.send_line_break()
  50.     self.nospace = 1
  51.     self.softspace = 0
  52.  
  53.     def add_hor_rule(self):
  54.     self.writer.send_hor_rule()
  55.     self.nospace = 1
  56.     self.softspace = 0
  57.  
  58.     def add_label_data(self, format, counter):
  59.     data = self.format_counter(format, counter)
  60.     self.writer.send_label_data(data)
  61.  
  62.     def format_counter(self, format, counter):
  63.     if counter <= 0:
  64.         return format
  65.         label = ''
  66.         for c in format:
  67.             try:
  68.                 if c == '1':
  69.             c = '%d' % counter
  70.                 elif c in 'aA':
  71.             c = self.format_letter(c, counter)
  72.                 elif c in 'iI':
  73.             c = self.format_roman(c, counter)
  74.             except:
  75.                 pass
  76.             label = label + c
  77.         return label
  78.  
  79.     def format_letter(self, case, counter):
  80.     label = ''
  81.     while counter > 0:
  82.         counter, x = divmod(counter-1, 26)
  83.         s = chr(ord(case) + x)
  84.         label = s + label
  85.     return label
  86.  
  87.     def format_roman(self, case, counter):
  88.         ones = ['i', 'x', 'c', 'm']
  89.         fives = ['v', 'l', 'd']
  90.         label = ''
  91.         index = 0
  92.     # This will die of IndexError when counter is too big
  93.         while counter > 0:
  94.             counter, x = divmod(counter, 10)
  95.             if x == 9:
  96.                 s = ones[index] + ones[index+1]
  97.             elif x == 4:
  98.                 s = ones[index] + fives[index]
  99.             else:
  100.                 if x >= 5:
  101.                     s = fives[index]
  102.                     x = x-5
  103.                 else:
  104.                     s = ''
  105.                 s = s + ones[index]*x
  106.             label = s + label
  107.             index = index + 1
  108.         if case == 'I': label = string.upper(label)
  109.         return label
  110.  
  111.     def add_flowing_data(self, data):
  112.     if not data: return
  113.     data = regsub.gsub(whitespace, ' ', data)
  114.     if self.nospace and data[0] == ' ':
  115.         data = data[1:]
  116.         if not data: return
  117.     elif self.softspace and data[0] != ' ':
  118.         data = ' ' + data
  119.     self.nospace = self.softspace = 0
  120.     if data[-1] == ' ':
  121.         data = data[:-1]
  122.         self.softspace = 1
  123.     self.writer.send_flowing_data(data)
  124.  
  125.     def add_literal_data(self, data):
  126.     if self.softspace and data[:1] != '\n':
  127.         data = ' ' + data
  128.     self.nospace = self.softspace = 0
  129.     self.writer.send_literal_data(data)
  130.  
  131.     def flush_softspace(self):
  132.     if self.softspace:
  133.         self.nospace = self.softspace = 0
  134.         self.writer.send_flowing_data(' ')
  135.  
  136.     def push_font(self, (size, i, b, tt)):
  137.     if self.font_stack:
  138.         csize, ci, cb, ctt = self.font_stack[-1]
  139.         if size is AS_IS: size = csize
  140.         if i is AS_IS: i = ci
  141.         if b is AS_IS: b = cb
  142.         if tt is AS_IS: tt = ctt
  143.     font = (size, i, b, tt)
  144.     self.font_stack.append(font)
  145.     self.writer.new_font(font)
  146.  
  147.     def pop_font(self):
  148.     if self.font_stack:
  149.         del self.font_stack[-1]
  150.     if self.font_stack:
  151.         font = self.font_stack[-1]
  152.     else:
  153.         font = None
  154.     self.writer.new_font(font)
  155.  
  156.     def push_margin(self, margin):
  157.     self.margin_stack.append(margin)
  158.     self.writer.new_margin(margin, len(self.margin_stack))
  159.  
  160.     def pop_margin(self):
  161.     if self.margin_stack:
  162.         del self.margin_stack[-1]
  163.     if self.margin_stack:
  164.         margin = self.margin_stack[-1]
  165.     else:
  166.         margin = None
  167.     self.writer.new_margin(margin, len(self.margin_stack))
  168.  
  169.     def set_spacing(self, spacing):
  170.     self.spacing = spacing
  171.     self.writer.new_spacing(spacing)
  172.  
  173.     def push_style(self, style):
  174.     self.style_stack.append(style)
  175.     self.writer.new_styles(tuple(self.style_stack))
  176.  
  177.     def pop_style(self):
  178.     if self.style_stack:
  179.         del self.style_stack[-1]
  180.     self.writer.new_styles(tuple(self.style_stack))
  181.  
  182.  
  183. class AbstractWriter:
  184.  
  185.     def __init__(self):
  186.     pass
  187.  
  188.     def new_font(self, font):
  189.     print "new_font(%s)" % `font`
  190.  
  191.     def new_margin(self, margin, level):
  192.     print "new_margin(%s, %d)" % (`margin`, level)
  193.  
  194.     def new_spacing(self, spacing):
  195.     print "new_spacing(%s)" % `spacing`
  196.  
  197.     def new_styles(self, styles):
  198.     print "new_styles(%s)" % `styles`
  199.  
  200.     def send_paragraph(self, blankline):
  201.     print "send_paragraph(%s)" % `blankline`
  202.  
  203.     def send_line_break(self):
  204.     print "send_line_break()"
  205.  
  206.     def send_hor_rule(self):
  207.     print "send_hor_rule()"
  208.  
  209.     def send_label_data(self, data):
  210.     print "send_label_data(%s)" % `data`
  211.  
  212.     def send_flowing_data(self, data):
  213.     print "send_flowing_data(%s)" % `data`
  214.  
  215.     def send_literal_data(self, data):
  216.     print "send_literal_data(%s)" % `data`
  217.  
  218.  
  219. class DumbWriter(AbstractWriter):
  220.  
  221.     def __init__(self, file=None, maxcol=72):
  222.     self.file = file or sys.stdout
  223.     self.maxcol = maxcol
  224.     AbstractWriter.__init__(self)
  225.     self.reset()
  226.  
  227.     def reset(self):
  228.     self.col = 0
  229.     self.atbreak = 0
  230.  
  231.     def send_paragraph(self, blankline):
  232.     self.file.write('\n' + '\n'*blankline)
  233.     self.col = 0
  234.     self.atbreak = 0
  235.  
  236.     def send_line_break(self):
  237.     self.file.write('\n')
  238.     self.col = 0
  239.     self.atbreak = 0
  240.  
  241.     def send_hor_rule(self):
  242.     self.file.write('\n')
  243.     self.file.write('-'*self.maxcol)
  244.     self.file.write('\n')
  245.     self.col = 0
  246.     self.atbreak = 0
  247.  
  248.     def send_literal_data(self, data):
  249.     self.file.write(data)
  250.     i = string.rfind(data, '\n')
  251.     if i >= 0:
  252.         self.col = 0
  253.         data = data[i+1:]
  254.     data = string.expandtabs(data)
  255.     self.col = self.col + len(data)
  256.     self.atbreak = 0
  257.  
  258.     def send_flowing_data(self, data):
  259.     if not data: return
  260.     atbreak = self.atbreak or data[0] in string.whitespace
  261.     col = self.col
  262.     maxcol = self.maxcol
  263.     write = self.file.write
  264.     for word in string.split(data):
  265.         if atbreak:
  266.         if col + len(word) >= maxcol:
  267.             write('\n')
  268.             col = 0
  269.         else:
  270.             write(' ')
  271.             col = col + 1
  272.         write(word)
  273.         col = col + len(word)
  274.         atbreak = 1
  275.     self.col = col
  276.     self.atbreak = data[-1] in string.whitespace
  277.  
  278.  
  279. def test(file = None):
  280.     w = DumbWriter()
  281.     f = AbstractFormatter(w)
  282.     if file:
  283.     fp = open(file)
  284.     elif sys.argv[1:]:
  285.     fp = open(sys.argv[1])
  286.     else:
  287.     fp = sys.stdin
  288.     while 1:
  289.     line = fp.readline()
  290.     if not line:
  291.         break
  292.     if line == '\n':
  293.         f.end_paragraph(1)
  294.     else:
  295.         f.add_flowing_data(line)
  296.     f.end_paragraph(0)
  297.  
  298.  
  299. if __name__ == '__main__':
  300.     test()
  301.